package dd.prog2.exercises.set04;

public class EfficientMatrix implements Matrix{

	int Mi, Mj;
	double[] m;
	int MiMj;

	protected EfficientMatrix(int i, int j){
		this.m = new double[i*j];
		this.Mi = i;
		this.Mj = j;
		MiMj = (Mj-1)*(Mi-1);
	}

	@Override
	public Matrix add(Matrix m2) throws ArithmeticException  {
		if((m2.getMi() != this.getMi()) || m2.getMj() != this.getMj())
			throw new ArithmeticException();
		Matrix res = new EfficientMatrix(Mi, Mj);
		for (int i = 0; i < this.Mi; i++) {
			for (int j = 0; j < this.Mj; j++) {
				res.setMij(this.getMij(i,j)+m2.getMij(i, j), i, j);
			}
		}
		return res;
	}

	@Override
	public Matrix sub(Matrix m2) throws ArithmeticException  {
		if((m2.getMi() != this.getMi()) || m2.getMj() != this.getMj())
			throw new ArithmeticException();
		Matrix res = new EfficientMatrix(Mi, Mj);
		for (int i = 0; i < this.Mi; i++) {
			for (int j = 0; j < this.Mj; j++) {
				res.setMij(this.getMij(i,j)-m2.getMij(i, j), i, j);
			}
		}
		return res;

	}

	@Override
	public Vector mul(Vector v) throws ArithmeticException  {
		if(v.getLength() != this.getMj())
			throw new ArithmeticException();
		Vector res = VectorMathFactory.createVector(Mj, false);
			for(int i = 0; i<Mi;i++){
				double value = 0;
				for (int j = 0; j < Mj; j++) {
					value += this.getMij(i, j)*v.getVi(j);
				}
				res.setVi(value, i);
			}
		return res;
	}

	@Override
	public double getMij(int i, int j) {
		return m[i+j+MiMj];
	}

	@Override
	public String toString() {
		String result = "M("+this.Mi+", "+this.Mj+") =\n";
		for (int i = 0; i < this.Mi; i++) {
			result += "\t";
			for (int j = 0; j < Mj; j++) {
				result += m[i+j+MiMj] + " ";
			}
			result += "\n";
		}
		return result;
	}

	@Override
	public void setMij(double value, int i, int j) {
		m[i+j+MiMj] = value;
	}

	@Override
	public void setall(double value) {
		for (int i = 0; i < Mi; i++) {
			for (int j = 0; j < Mj; j++) {
				m[i+j+MiMj] = value;
			}
		}
	}

	@Override
	public int getMi() {
		return Mi;
	}

	@Override
	public int getMj() {
		return Mj;
	}
}
